<?php
declare(strict_types=1);

namespace Zms\Request\Driver;

use Swoole\Coroutine\Http\Client;
use Zms\Request\Http;
use Zms\Request\RequestAbstract;
use Zms\Request\Result;


/**
 * @describe  SWOOLE驱动的网络请求,必须在协程环境下执行,已知在cygwin环境下不可用（含swoole-cli）
 * @user zlf <zms-pro@qq.com> 2025/3/13
 */
class Swoole extends RequestAbstract
{
    public function execute(string $url, array $query = []): Result
    {
        try {
            $uri = $this->extractTargetAddress($this->setLink($url, $query));

            $client = new Client($uri['host'], $uri['port'], $uri['https']);

            //设置请求方式
            $client->setMethod($this->method);

            //设置请求超时间
            $client->set([
                'timeout' => $this->timeout
            ]);

            //设置POST请求参数
            if (!is_null($this->data)) {
                $client->setData($this->data);
            }

            //设置请求header
            if (count($this->headers) > 0) {
                $client->setHeaders($this->headers);
            }

            //设置请求cookies
            if (count($this->cookies) > 0) {
                $client->setCookies($this->cookies);
            }

            //发起请求
            $status = $client->execute($uri['path']);
            //关闭请求
            $client->close();
            if ($status) {
                return new Result((int)$client->statusCode, '请求完成', $client->body, Http::SWOOLE);
            }
            return new Result((int)$client->statusCode, '请求完成', null, Http::SWOOLE);
        } catch (\Exception $exception) {
            return new Result(0, $exception->getMessage(), null, Http::SWOOLE);
        }
    }


    /**
     * @describe 解析请求信息
     * @user zlf <zms-pro@qq.com> 2025/3/13
     * @param string $url
     * @return array{host:string,port:int,path:string,https:bool}
     */
    private function extractTargetAddress(string $url): array
    {
        $uri = parse_url($url);
        $port = $uri['port'] ?? 0;
        $https = $uri['scheme'] === 'https';
        $path = '';
        if (isset($uri['path']) && $uri['path']) {
            $path = $uri['path'];
        } else {
            $path = '/';
        }
        if (isset($uri['query'])) {
            $path .= '?' . $uri['query'];
        }
        if (isset($uri['fragment'])) {
            $path .= '#' . $uri['fragment'];
        }
        return [
            'host' => $uri['host'],
            'port' => intval($port ?: ($https ? 443 : 80)),
            'path' => $path,
            'https' => $https
        ];
    }
}